﻿using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using Foundation;

namespace Poet.ViewModels
{
    /// <summary>
    /// Look In View Model.
    /// </summary>
    /// <typeparam name="TItem">The type of the item.</typeparam>
    internal class LookInViewModel<TItem> : ViewModel where TItem : class
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="LookInViewModel&lt;TItem&gt;"/> class.
        /// </summary>
        /// <param name="items">The items.</param>
        public LookInViewModel(ObservableCollection<TItem> items)
        {
            CheckAll = new Command(OnCheckAllExecute);
            UncheckAll = new Command(OnUncheckExecute);
            Items = new ObservableCollection<TItem>(items);
            SelectedItems = new ObservableCollection<TItem>();

            items.CollectionChanged += (o, e) =>
                {
                    if (e.OldItems != null)
                        foreach (TItem item in e.OldItems)
                            Items.Remove(item);

                    if (e.NewItems != null)
                        foreach (TItem item in e.NewItems)
                            Items.Add(item);

                    if (e.OldItems == null) return;

                    foreach (var item in e.OldItems.Cast<TItem>().Where(view => SelectedItems.Contains(view)))
                        SelectedItems.Remove(item);
                };

            var lastActiveItemCheckState = false;
            var lastActiveDocumentView = ActiveItem;
            PropertyChanged += (o, e) =>
                {
                    var propertyName = PropertyNameProvider.GetPropertyName(() => ActiveItem);
                    if (e.PropertyName != propertyName) return;

                    if (ActiveItem != null && !Equals(ActiveItem, lastActiveDocumentView))
                        lastActiveItemCheckState = SelectedItems.Contains(ActiveItem);

                    if (!LastActiveItemCheckState && lastActiveDocumentView != null)
                        SelectedItems.Remove(lastActiveDocumentView);

                    if (ActiveItem != null && !SelectedItems.Contains(ActiveItem))
                        SelectedItems.Add(ActiveItem);

                    LastActiveItemCheckState = lastActiveItemCheckState;
                    lastActiveDocumentView = ActiveItem;
                };
        }

        /// <summary>
        /// Gets or sets the check all.
        /// </summary>
        /// <value>
        /// The check all.
        /// </value>
        public ICommand CheckAll { get; protected set; }

        /// <summary>
        /// Gets or sets the uncheck all.
        /// </summary>
        /// <value>
        /// The uncheck all.
        /// </value>
        public ICommand UncheckAll { get; protected set; }

        /// <summary>
        /// Gets or sets the selected items.
        /// </summary>
        /// <value>
        /// The selected items.
        /// </value>
        public ObservableCollection<TItem> SelectedItems { get; protected set; }

        /// <summary>
        /// Gets or sets the items.
        /// </summary>
        /// <value>
        /// The items.
        /// </value>
        public ObservableCollection<TItem> Items { get; protected set; }

        /// <summary>
        /// Gets or sets a value indicating whether [active document view last check state].
        /// </summary>
        /// <value>
        /// 	<c>true</c> if [active document view last check state]; otherwise, <c>false</c>.
        /// </value>
        public bool LastActiveItemCheckState { get; set; }

        /// <summary>
        /// Gets or sets the document view for move.
        /// </summary>
        /// <value>
        /// The document view for move.
        /// </value>
        public TItem ItemForMove
        {
            get { return Get(() => ItemForMove); }
            set { Set(() => ItemForMove, value); }
        }

        /// <summary>
        /// Gets or sets the active item.
        /// </summary>
        /// <value>
        /// The active item.
        /// </value>
        public TItem ActiveItem
        {
            get { return Get(() => ActiveItem); }
            set { Set(() => ActiveItem, value); }
        }

        private void OnUncheckExecute(object parameter)
        {
            LastActiveItemCheckState = false;
            foreach (var item in Items.Where(item => SelectedItems.Contains(item) && !Equals(item, ActiveItem)))
            {
                SelectedItems.Remove(item);
            }
        }

        private void OnCheckAllExecute(object parameter)
        {
            LastActiveItemCheckState = true;
            foreach (var item in Items.Where(item => !SelectedItems.Contains(item)))
            {
                SelectedItems.Add(item);
            }
        }
    }
}
